package com.ubird.astar.core;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

public class AStarNode implements Comparable<AStarNode> {
	private static Table<Integer, Integer, Integer> GMatrix = HashBasedTable
			.create();
	static {
		GMatrix.put(0, 0, 10);
		GMatrix.put(0, -1, 10);
		GMatrix.put(1, -1, 14);
		GMatrix.put(1, 0, 10);
		GMatrix.put(1, 1, 14);
		GMatrix.put(0, 1, 10);
		GMatrix.put(-1, 1, 14);
		GMatrix.put(-1, 0, 10);
		GMatrix.put(-1, -1, 10);
	}

	private int g; // 从起点source移动到当前点的耗费
	private int h; // 从当前点到终点的估值耗费
	private int f; // f = g + h

	private int x;
	private int y;

	private AStarNode father; // 父结点

	public AStarNode(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public AStarNode getFather() {
		return father;
	}

	public void setFather(AStarNode father) {
		this.father = father;
	}

	public void init(AStarNode target) {
		this.g = 0;
		this.h = heuristicCostEstimate(this, target);
		this.f = g + h;
	}

	/**
	 * 计算H
	 * 
	 * @param source
	 * @param target
	 * @return
	 */
	public int heuristicCostEstimate(AStarNode source, AStarNode target) {
		return (Math.abs(source.x - target.x) + Math.abs(source.y - target.y))
				* GMatrix.get(0, 0);
	}

	@Override
	public int compareTo(AStarNode o) {
		return this.f < o.f ? -1 : 1;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof AStarNode)) {
			return false;
		}
		
		AStarNode node = (AStarNode) obj;
		return node.x == this.x && node.y == this.y;
	}

	@Override
	public String toString() {
		return x + ", " + y;
	}

	public int calculatorF(AStarNode father, AStarNode target) {
		this.g = getDistinctG(father);
		this.h = heuristicCostEstimate(this, target);
		this.f = g + h;
		this.father = father;
		return f;
	}

	public int getDistinctG(AStarNode father) {
		int offsetX = x - father.x;
		int offsetY = y - father.y;
		return GMatrix.get(offsetX, offsetY) + father.g;
	}

	public int getG() {
		return g;
	}

	/**
	 * 是否比指定的点更好
	 * 
	 * @param node
	 * @return
	 */
	public boolean isBetter(AStarNode node) {
		return isGBetter(node);
	}

	public boolean isGBetter(AStarNode node) {
		return g + getDistinctG(node) < node.g;
	}

	public boolean isFBetter(AStarNode node) {
		return f < node.f;
	}

	public int getF() {
		return f;
	}
}